#include <math.h>

#include <iostream>
#include <string>
#include <vector>
#include <chrono>

#include "waveform.h"
#include "indication.h"

using namespace std;
using namespace std::chrono;
using namespace ch;

namespace ch {
    class ScopedTimer {
        public:
            ScopedTimer(string tag): mTag(tag), mTs() {
                mTs = GetCurrentTs();
                cout << ">>>>>>>> Timer [" << mTag << "] start." << endl;
            }
            void reSet(string tag) {
                finish();
                mTag = tag;
                mTs = GetCurrentTs();
                cout << ">>>>>>>> Timer [" << mTag << "] start." << endl;
            }
            void finish() {
                milliseconds current=GetCurrentTs();
                cout << "<<<<<<<< Timer [" << mTag << "] finished:" << (current.count() - mTs.count()) << "ms" << endl << endl;
            }
            ~ScopedTimer() {
                finish();
            }
        private:
            string mTag;
            milliseconds mTs;
            inline milliseconds GetCurrentTs() {
                return duration_cast<milliseconds>(system_clock::now().time_since_epoch());
            }

    };


    std::string GetChannelName(Channel ch) {
        switch(ch) {
            case I:
                return "I";
            case II:
                return "II";
            case III:
                return "III";
            case aVR:
                return "aVR";
            case aVL:
                return "aVL";
            case aVF:
                return "aVF";
            case V1:
                return "V1";
            case V2:
                return "V2";
            case V3:
                return "V3";
            case V4:
                return "V4";
            case V5:
                return "V5";
            case V6:
                return "V6";
            default:
                return "UNKNOWN";
        }
    }
    
    
    void printIndication(Waveform * wf) {
        Indication indication;
        wf->GetIndication(indication);
        cout << "HR\t:" << round(indication.HBR) << " bpm" <<endl;
        cout << "P\t:" << indication.PDuration << " ms" <<endl;
        cout << "PR\t:" << indication.PRInterval << " ms" <<endl;
        cout << "QRS\t:" << indication.QRSDuration << " ms" <<endl;
        cout << "QT/QTc\t:" << indication.QTInterval << "/"<< indication.QTcInterval<< " ms" <<endl;
        cout << "P/QRS/T\t:" << indication.PAxis << "/"<< indication.QRSAxis << "/"<< indication.TAxis << " deg." <<endl;
        cout << "RV5/SV1\t:" << indication.RV5 << "/" << indication.SV1 << " mV" <<endl;
        cout << "RV6/SV2\t:" << indication.RV6 << "/" << indication.SV2 << " mV" <<endl;
    }
    
    void testLoadFile(Waveform* wf, const string dataPath, const string hbPath) {
        ScopedTimer t("testLoadFile");
        wf->Load(dataPath, hbPath);
    
        vector<Heartbeat> hbs = wf->GetHeartbeats();
        cout<< "Channel:" << GetChannelName(III);
        for (size_t i=0;i<TagCount;i++) {
            cout << "," << hbs[0].tags[III][i];
        }
        cout<<endl;

        size_t c = hbs.size();
        cout<< "Combine Ps:";
        for(size_t i=0; i<c; i++) {
            cout<< "," << hbs[i].combineTags[Ps];
        }
        cout<<endl;

        printIndication(wf);
    }


    void testSaveFile(Waveform* wf, string dataPath, string heartbeatPath) {
        ScopedTimer t("testSaveFile");
        wf -> Save(dataPath, heartbeatPath);
    }
    
    void testSwap(Waveform* wf) {
        ScopedTimer t("testSwap");
        wf->SwapChannel(I,II);
        printIndication(wf);
        wf->ReverseChannel(V1);
        printIndication(wf);
        wf->ReverseChannel(V1);
    }
    
    
    void testModifyChannel(Waveform* wf) {
        ScopedTimer t("testModifyChannel");
        wf->SetHeartbeatChannels(II, None, None);
        printIndication(wf);
        wf->SetHeartbeatChannels(II, V1, V5);
        printIndication(wf);
    }
    
    
    void testModifyHeartbeat(Waveform* wf) {
        ScopedTimer t("testModifyHeartbeat");
        vector<Heartbeat> hbs=wf->GetHeartbeats();
        size_t c = hbs.size();
        for(size_t i=0;i<c;i++) {
            Heartbeat tmp = hbs[i];
            tmp.combineTags[Ps] -= 10;
            wf->SetHeartbeat(tmp, i);
        }
        printIndication(wf);
    }
}


int main(int argc, char** argv) {
    if (argc != 3) {
        std::cout << "demo.exe <dataPath> <heartbeatPath>" << std::endl;
        return -1;
    }
    std::string dataPath(argv[1]);
    std::string heartbeatPath(argv[2]);
    Waveform wf;

    testLoadFile(&wf, dataPath, heartbeatPath);
    testSaveFile(&wf, dataPath+".new", heartbeatPath+".new");
    testSwap(&wf);
    testModifyChannel(&wf);
    testModifyHeartbeat(&wf);
}


